'''
距离计算
文件读写操作
其他通用功能
'''
import math
import os
import sys

import Globals
import copy


# 从文件名获取数据
def get_data(distance_file, time_file, spec_file):
    c_num = Globals.customer_num
    # 初始化peerTime, peerDistance, 和customer列表
    Globals.peer_time = [[0.0 for _ in range(c_num + 2)] for _ in range(c_num + 2)]
    Globals.peer_distance = [[0.0 for _ in range(c_num + 2)] for _ in range(c_num + 2)]
    Globals.customer = [Globals.Customer() for _ in range(c_num + 2)]
    Globals.max_delay_time = [1800 for _ in range(c_num + 2)]

    # 读取规格文件
    with open(spec_file, 'r') as f_spec:
        # 跳过文件的前四行
        for _ in range(4): next(f_spec)
        # 读取最大容量值
        specLine = f_spec.readline().strip().split()
        Globals.vehicle_num = int(specLine[0])
        Globals.max_capacity = float(specLine[1])

        # 再次跳过四行
        for _ in range(4): next(f_spec)
        # 读取客户信息
        for i in range(c_num + 1):
            data = f_spec.readline().split()
            Globals.customer[i].id = int(data[0])
            Globals.customer[i].x = float(data[1])
            Globals.customer[i].y = float(data[2])
            Globals.customer[i].delivery_demand = float(data[3])
            Globals.customer[i].pick_up_demand = float(data[4])
            Globals.customer[i].begin_time = float(data[5])
            Globals.customer[i].end_time = float(data[6])
            Globals.customer[i].server_time = float(data[7])
    Globals.customer[c_num + 1] = Globals.customer[0]

    # 打印测试数据
    # for i in range(len(Globals.customer)):
    #     print(
    #         "ID: {}, X: {}, Y: {}, Delivery Demand: {}, Pick-up Demand: {}, Start Time: {}, "
    #         "End Time: {}, Service Time: {}".format(
    #             Globals.customer[i].id, Globals.customer[i].x, Globals.customer[i].y,
    #             Globals.customer[i].delivery_demand, Globals.customer[i].pick_up_demand,
    #             Globals.customer[i].begin_time, Globals.customer[i].end_time, Globals.customer[i].server_time))

    # 读取时间文件和距离文件
    with open(time_file, 'r') as f_time, open(distance_file, 'r') as f_distance:
        for i in range(c_num + 1):
            # 读取一行数据并按空格分割
            time_line = f_time.readline().strip().split()
            for j in range(len(time_line)):
                Globals.peer_time[i][j] = float(time_line[j])
            # 将字符串列表转换为浮点数列表，并赋值给 peerTime 的第 i 行
            distance_line = f_distance.readline().strip().split()
            for j in range(len(distance_line)):
                Globals.peer_distance[i][j] = float(distance_line[j])

    # 处理特殊情况
    # 即将配送中心到客户i的距离设置为客户i到配送中心，即终点的距离
    for i in range(c_num + 2):
        Globals.peer_time[i][c_num + 1] = Globals.peer_time[i][0]
        Globals.peer_distance[i][c_num + 1] = Globals.peer_distance[i][0]
        Globals.peer_time[c_num + 1][i] = Globals.peer_time[0][i]
        Globals.peer_distance[c_num + 1][i] = Globals.peer_distance[0][i]

    # 打印测试数据
    # print("Peer Time Matrix:")
    # for i in range(c_num + 2):  # 假设包括了配送中心作为起点和终点
    #     for j in range(c_num + 2):
    #         print(f"{Globals.peer_time[i][j]:.2f}", end=' ')
    #     print()  # 新的一行开始前打印一个换行符
    #
    # print("\nPeer Distance Matrix:")
    # for i in range(c_num + 2):
    #     for j in range(c_num + 2):
    #         print(f"{Globals.peer_distance[i][j]:.2f}", end=' ')
    #     print()  # 新的一行开始前打印一个换行符


def get_distance(route):
    # 计算总送货量和取货量
    size = len(route.customers)
    route.delivery_capacity = 0
    route.pick_up_capacity = 0
    for i in range(1, size - 1):
        cust = route.customers[i]
        route.delivery_capacity += Globals.customer[cust].delivery_demand
        route.pick_up_capacity += Globals.customer[cust].pick_up_demand

    # 初始化路线的总行驶距离为0
    route.travel_dist = 0

    # 计算总行驶距离并重置a_distance和b_distance
    for i in range(len(route.customers) - 1):
        cur_cust = route.customers[i]
        next_cust = route.customers[i + 1]
        route.travel_dist += Globals.peer_distance[cur_cust][next_cust]
        Globals.a_distance[cur_cust] = 0
        Globals.b_distance[cur_cust] = 0

    # 计算从路线起点到每个客户点的累计距离
    Globals.b_distance[route.customers[0]] = 0
    for i in range(1, len(route.customers) - 1):
        pre_cust = route.customers[i - 1]
        cur_cust = route.customers[i]
        Globals.b_distance[cur_cust] = (
                Globals.b_distance[pre_cust] + Globals.peer_distance[pre_cust][cur_cust]
        )

    # 计算从每个客户点到路线终点的累计距离
    for i in range(len(route.customers) - 2, 0, -1):
        cur_cust = route.customers[i]
        next_cust = route.customers[i + 1]
        Globals.a_distance[cur_cust] = (
                Globals.a_distance[next_cust] + Globals.peer_distance[cur_cust][next_cust]
        )


def get_time(route):
    # 初始化变量
    route.travel_time = 0
    route.delay_time = 0
    route.wait_time = 0
    Globals.total_wait[0] = 0
    Globals.total_delay[0] = 0
    # 遍历所有客户
    for i in range(len(route.customers) - 1):

        cur_cust = route.customers[i]
        next_cust = route.customers[i + 1]

        wait = delay = 0
        # 旅行时间
        route.travel_time += Globals.peer_time[cur_cust][next_cust]
        # 到达客户时间
        Globals.a_time[next_cust] = route.travel_time

        # 如果到达下一个客户的时间超过了该客户的最晚服务时间
        # 则将超出的时间视为延误，累加到route.delay_time并更新total_delay数组
        if route.travel_time > Globals.customer[next_cust].end_time:
            delay = route.travel_time - Globals.customer[next_cust].end_time
        route.delay_time += delay
        Globals.total_delay[next_cust] = Globals.total_delay[cur_cust] + delay

        # 如果到达时间早于客户的最早服务时间
        # 则需要等待，等待时间累加到route.wait_time并更新w_time和total_wait数组
        if route.travel_time < Globals.customer[next_cust].begin_time:
            wait = Globals.customer[next_cust].begin_time - route.travel_time
        Globals.w_time[next_cust] = wait
        Globals.total_wait[next_cust] = Globals.total_wait[next_cust] + wait
        route.wait_time += wait

        # 对于每个客户，行驶时间需要加上在该客户处的等待时间和服务时间(s_time)
        route.travel_time += (wait + Globals.customer[next_cust].server_time)
        Globals.l_time[next_cust] = route.travel_time

    # 初始化起点的离开时间和最大等待时间
    Globals.l_time[route.customers[0]] = 0
    Globals.max_wait[route.customers[0]] = Globals.customer[route.customers[0]].end_time - Globals.a_time[
        route.customers[0]]

    # 从路线的倒数第二个客户开始向起点方向更新max_wait
    for i in range(len(route.customers) - 2, 0, -1):
        current_customer = route.customers[i]
        next_customer = route.customers[i + 1]
        # 更新max_wait为当前客户的最晚服务时间加上允许的最大延误减去到达当前客户的累计时间
        # 和下一个客户的max_wait加上当前客户的等待时间的较小值
        Globals.max_wait[current_customer] = min(
            # 客户的最晚服务时间加上允许的最大延误减去到达该客户的实际时间
            Globals.customer[current_customer].end_time + Globals.max_delay_time[current_customer] - Globals.a_time[
                current_customer],
            # 下一个客户的 max_wait 加上当前客户的等待时间
            Globals.w_time[current_customer] + Globals.max_wait[next_customer]
        )

    # 重置起点的总等待时间和总延误时间为0
    Globals.total_wait[route.customers[0]] = 0
    Globals.total_delay[route.customers[0]] = 0


# 对染色体的每个目标函数值进行转换，并存储在box_f数组中
def get_box(chrome):
    for i in range(Globals.FUNC_NUM):
        if chrome.f[i] == 0:
            chrome.box_f[i] = 0
        else:
            chrome.box_f[i] = math.log(chrome.f[i]) / math.log(1 + Globals.epsilon)


# 为染色体计算多个目标函数的值
def get_f(chromosome):
    # 初始化目标函数值
    chromosome.f = [0] * Globals.FUNC_NUM
    # 目标函数1：路线（车辆）数量
    chromosome.f[0] = len(chromosome.routes)
    # 目标函数2：总行驶距离
    chromosome.f[1] = sum(route.travel_dist for route in chromosome.routes)
    # 目标函数3：最长行驶时间
    # t_time = 0
    # r = None
    # for route in chromosome.routes:
    #     if route.travel_time > t_time:
    #         t_time = route.travel_time
    #         r = route
    # print(t_time,r.customers)
    chromosome.f[2] = max(route.travel_time for route in chromosome.routes) if chromosome.routes else 0
    # 目标函数4：总等待时间
    chromosome.f[3] = sum(route.wait_time for route in chromosome.routes)
    # 目标函数5：总延误时间
    chromosome.f[4] = sum(route.delay_time for route in chromosome.routes)

# 比较两个染色体在多个目标上的性能
def is_better(chrome_1, chrome_2):
    better = False
    # print("isbetter")
    # for value in chrome_1.f:
    #     print(f"chrome_1:{value:.6f} ", end="")
    # print()
    # for value in chrome_2.f:
    #     print(f"chrome_2:{value:.6f} ", end="")
    # print()
    for i in range(Globals.FUNC_NUM):
        # 如果chrome_2在至少一个目标上比chrome_1好
        # print(f"chrome_2.f[{i}]-chrome_1.f[{i}]={chrome_2.f[i] - chrome_1.f[i]}")
        if chrome_2.f[i] - chrome_1.f[i] > 0.000001:
            better = True
        #  并且chrome_1在所有目标上都不比chrome_2好
        if chrome_1.f[i] - chrome_2.f[i] > 0.000001:
            return False
    # 则chrome_1非支配chrome_2
    return better


# 比较的是经过转换的目标值
def is_better_box(chrome_1, chrome_2):
    better = False
    for i in range(Globals.FUNC_NUM):
        if chrome_2.box_f[i] - chrome_1.box_f[i] > 0.000001:
            better = True
        if chrome_1.box_f[i] - chrome_2.box_f[i] > 0.000001:
            return False
    return better


# 判断两个染色体在所有目标上的值是否相等
def is_equal(chrome_1, chrome_2):
    for i in range(Globals.FUNC_NUM):
        if abs(chrome_1.f[i] - chrome_2.f[i]) > 0.000001:
            return False
    return True


# 类似于is_equal，但是对比的是box_f数组，即经过某种处理的目标函数值
def is_equal_box(chrome_1, chrome_2):
    for i in range(Globals.FUNC_NUM):
        if abs(chrome_1.box_f[i] - chrome_2.box_f[i]) > 0.000001:
            return False
    return True


# 检查染色体是否在至少一个目标上比当前已知的极值解更好
def is_extreme(chrome):
    for index in range(Globals.FUNC_NUM):
        if Globals.extreme[index].f[index] - chrome.f[index] > 0.000001:
            return True
    return False


def output(f):
    Globals.final_EP.sort()
    for i, chromo in enumerate(Globals.final_EP):
        print(" ".join([f"{val:.6f}" for val in chromo.f]), file=f)

